/*
 * Copyright (c) 2022 Winner Microelectronics Co., Ltd. All rights reserved.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*****************************************************************************
*
* File Name : wm_param.c
*
* Description: param manager Module
*
* Copyright (c) 2014 Winner Micro Electronic Design Co., Ltd.
* All rights reserved.
*
* Author : dave
*
* Date : 2014-6-12
*****************************************************************************/
#include <string.h>
#include "wm_debug.h"
#include "wm_efuse.h"
#include "wm_flash.h"
#include "wm_internal_flash.h"
#include "wm_params.h"
#include "wm_mem.h"
#include "utils.h"
#include "wm_flash_map.h"
#include "wm_crypto_hard.h"
#include "wm_param.h"

#define USE_TWO_RAM_FOR_PARAMETER  0
static struct tls_param_flash flash_param;
#if USE_TWO_RAM_FOR_PARAMETER
static struct tls_sys_param sram_param;
#endif

struct tls_sys_param *user_default_param = NULL;
struct tls_sys_param *tls_param_user_param_init(void);

static tls_os_sem_t *sys_param_lock = NULL;
static const u8 factory_default_hardware[8] = {'H', 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
u8 updp_mode; // upadate default parameters mode, 0:not updating or up finish; 1:updating

static int param_flash_verify(u32 data_addr, u8 *data_buffer, u32 len)
{
    int err;
    u8 *buffer;

    buffer = tls_mem_alloc(len);
    if (buffer == NULL) {return 0;}

    do {
        err = tls_fls_read(data_addr, buffer, len);
        if (err != TLS_FLS_STATUS_OK) {
            err = 0;
            break;
        }

        if (memcmp(buffer, data_buffer, len) == 0) {
            err = 1;
        } else {
            err = 0;
        }
    } while (0);

    tls_mem_free(buffer);

    return err;
}

static int param_to_flash(int id, int modify_count, int partition_num)
{
    int err;
#if USE_TWO_RAM_FOR_PARAMETER
    struct tls_sys_param *src;
    struct tls_sys_param *dest;
#endif

    if ((id < TLS_PARAM_ID_ALL) || (id >= TLS_PARAM_ID_MAX)) {return TLS_PARAM_STATUS_EINVALID;}

    err = TLS_PARAM_STATUS_OK;

#if USE_TWO_RAM_FOR_PARAMETER
    src = &sram_param;
    dest = &flash_param.parameters;

    switch (id) {
        case TLS_PARAM_ID_ALL:
            MEMCPY(dest, src, sizeof(struct tls_sys_param));
            break;

        case TLS_PARAM_ID_SSID:
            MEMCPY(&dest->ssid, &src->ssid, sizeof(struct tls_param_ssid));
            break;

        case TLS_PARAM_ID_ENCRY:
            dest->encry = src->encry;
            break;

        case TLS_PARAM_ID_KEY:
            MEMCPY(&dest->key, &src->key, sizeof(struct tls_param_key));
            break;

        case TLS_PARAM_ID_IP:
            MEMCPY(&dest->ipcfg, &src->ipcfg, sizeof(struct tls_param_ip));
            break;

        case TLS_PARAM_ID_AUTOMODE:
            dest->auto_mode = src->auto_mode;
            break;

        case TLS_PARAM_ID_DEFSOCKET:
            MEMCPY(&dest->remote_socket_cfg, &src->remote_socket_cfg, sizeof(struct tls_param_socket));
            break;

        case TLS_PARAM_ID_BSSID:
            MEMCPY(&dest->bssid, &src->bssid, sizeof(struct tls_param_bssid));
            break;

        case TLS_PARAM_ID_CHANNEL:
            dest->channel = src->channel;
            break;

        case TLS_PARAM_ID_CHANNEL_EN:
            dest->channel_enable = src->channel_enable;
            break;

        case TLS_PARAM_ID_COUNTRY_REGION:
            dest->wireless_region = src->wireless_region;
            break;

        case TLS_PARAM_ID_WPROTOCOL:
            dest->wireless_protocol = src->wireless_protocol;
            break;

        case TLS_PARAM_ID_ADHOC_AUTOCREATE:
            dest->auto_create_adhoc = src->auto_create_adhoc;
            break;

        case TLS_PARAM_ID_ROAMING:
            dest->auto_roam = src->auto_roam;
            break;

        case TLS_PARAM_ID_AUTO_RETRY_CNT:
            dest->auto_retrycnt = src->auto_retrycnt;
            break;

        case TLS_PARAM_ID_WBGR:
            MEMCPY(&dest->wbgr, &src->wbgr, sizeof(struct tls_param_bgr));
            break;

        case TLS_PARAM_ID_USRINTF:
            dest->user_port_mode = src->user_port_mode;
            break;
        case TLS_PARAM_ID_ESCAPE_CHAR:
            dest->EscapeChar = src->EscapeChar;
            break;

        case TLS_PARAM_ID_ESCAPE_PERIOD:
            dest->EscapePeriod = src->EscapePeriod;
            break;

        case TLS_PARAM_ID_AUTO_TRIGGER_LENGTH:
            dest->transparent_trigger_length = src->transparent_trigger_length;
            break;

        case TLS_PARAM_ID_AUTO_TRIGGER_PERIOD:
            dest->transparent_trigger_period = src->transparent_trigger_period;
            break;

        case TLS_PARAM_ID_DEBUG_MODE:
            dest->debug_mode = src->debug_mode;
            break;

        case TLS_PARAM_ID_HARDVERSION:
            MEMCPY(&dest->hardware_version, &src->hardware_version, sizeof(struct tls_param_hardware_version));
            break;

        case TLS_PARAM_ID_BRDSSID:
            dest->ssid_broadcast_enable = src->ssid_broadcast_enable;
            break;

        case TLS_PARAM_ID_DNSNAME:
            MEMCPY(dest->local_dnsname, src->local_dnsname, 32);
            break;

        case TLS_PARAM_ID_DEVNAME:
            MEMCPY(dest->local_device_name, src->local_device_name, 32);
            break;

        case TLS_PARAM_ID_PSM:
            dest->auto_powersave = src->auto_powersave;
            break;

        case TLS_PARAM_ID_ORAY_CLIENT:
            MEMCPY(&dest->oray_client_setting, &src->oray_client_setting, sizeof(struct tls_param_oray_client));
            break;

        case TLS_PARAM_ID_UPNP:
            dest->upnp_enable = src->upnp_enable;
            break;

        case TLS_PARAM_ID_UART:
            MEMCPY(&dest->uart_cfg, &src->uart_cfg, sizeof(struct tls_param_uart));
            break;
#if TLS_CONFIG_WPS
        case TLS_PARAM_ID_WPS:
            MEMCPY(&dest->wps, &src->wps, sizeof(struct tls_param_wps));
            break;
#endif
        case TLS_PARAM_ID_CHANNEL_LIST:
            dest->channellist = src->channellist;
            break;
        case TLS_PARAM_ID_ONESHOT_CFG:
            dest->oneshotflag = src->oneshotflag;
            break;
        case TLS_PARAM_ID_SHA1:
            MEMCPY(&dest->psk, &src->psk, sizeof(struct tls_param_sha1));
            break;
        case TLS_PARAM_ID_ORIGIN_KEY:
            MEMCPY(&dest->original_key, &src->original_key, sizeof(struct tls_param_original_key));
            break;
        case TLS_PARAM_ID_ORIGIN_SSID:
            MEMCPY(&dest->original_ssid, &src->original_ssid, sizeof(struct tls_param_ssid));
            break;
        case TLS_PARAM_ID_AUTO_RECONNECT:
            dest->auto_reconnect = src->auto_reconnect;
            break;

        case TLS_PARAM_ID_IO_MODE:
            dest->IoMode = src->IoMode;
            break;

        case TLS_PARAM_ID_CMD_MODE:
            dest->CmdMode = src->CmdMode;
            break;

        case TLS_PARAM_ID_PASSWORD:
            MEMCPY(dest->PassWord, src->PassWord, sizeof(src->PassWord));
            break;

        case TLS_PARAM_ID_WEBS_CONFIG:
            dest->WebsCfg = src->WebsCfg;
            break;
        case TLS_PARAM_ID_QUICK_CONNECT:
            MEMCPY(&dest->quick_connect, &src->quick_connect, sizeof(struct tls_param_quick_connect));
            break;
        case TLS_PARAM_ID_KEY_CHANGE:
            dest->key_changed = src->key_changed;
            break;
        case TLS_PARAM_ID_SSID_CHANGE:
            dest->ssid_changed = src->ssid_changed;
            break;
#if TLS_CONFIG_AP
        case TLS_PARAM_ID_SOFTAP_SSID:
            MEMCPY(&dest->apsta_ssid, &src->apsta_ssid, sizeof(struct tls_param_ssid));
            break;
        case TLS_PARAM_ID_SOFTAP_PSK:
            MEMCPY(&dest->apsta_psk, &src->apsta_psk, sizeof(struct tls_param_sha1));
            break;
        case TLS_PARAM_ID_SOFTAP_ENCRY:
            dest->encry4softap = src->encry4softap;
            break;
        case TLS_PARAM_ID_SOFTAP_KEY:
            MEMCPY(&dest->key4softap, &src->key4softap, sizeof(struct tls_param_key));
            break;
        case TLS_PARAM_ID_SOFTAP_IP:
            MEMCPY(&dest->ipcfg4softap, &src->ipcfg4softap, sizeof(struct tls_param_ip));
            break;
        case TLS_PARAM_ID_SOFTAP_CHANNEL:
            dest->channel4softap = src->channel4softap;
            break;
        case TLS_PARAM_ID_SOFTAP_WBGR:
            MEMCPY(&dest->wbgr4softap, &src->wbgr4softap, sizeof(struct tls_param_bgr));
            break;
#endif
        case TLS_PARAM_ID_SNTP_SERVER1:
            strncpy(dest->sntp_service1, src->sntp_service1, strlen(src->sntp_service1) + 1);
            break;
        case TLS_PARAM_ID_SNTP_SERVER2:
            strncpy_s(dest->sntp_service2, sizeof(dest->sntp_service2), src->sntp_service2,
                strlen(src->sntp_service2) + 1);
            break;
        case TLS_PARAM_ID_SNTP_SERVER3:
            strncpy(dest->sntp_service3, src->sntp_service3, strlen(src->sntp_service3) + 1);
            break;
        case TLS_PARAM_ID_TEM_OFFSET:
            MEMCPY(&dest->params_tem, &src->params_tem, sizeof(struct tls_param_tem_offset));
            break;

        case TLS_PARAM_ID_BT_ADAPTER:
            MEMCPY(&dest->adapter_t, &src->adapter_t, sizeof(bt_adapter_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_1:
            MEMCPY(&dest->remote_device1, &src->remote_device1, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_2:
            MEMCPY(&dest->remote_device2, &src->remote_device2, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_3:
            MEMCPY(&dest->remote_device3, &src->remote_device3, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_4:
            MEMCPY(&dest->remote_device4, &src->remote_device4, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_5:
            MEMCPY(&dest->remote_device5, &src->remote_device5, sizeof(bt_remote_device_t));
            break;
        default:
            err = TLS_PARAM_STATUS_EINVALIDID;
            goto exit;
    }
#endif
    flash_param.magic = TLS_PARAM_MAGIC;
    flash_param.length = sizeof(flash_param);

    if (modify_count < 0) {
        flash_param.modify_count ++;
        TLS_DBGPRT_INFO("update the \"modify count(%d)\".\n", flash_param.modify_count);
    } else {
        flash_param.modify_count  = modify_count;
        TLS_DBGPRT_INFO("initialize the \"modify count(%d)\".\n", flash_param.modify_count);
    }

    if (partition_num < 0) {
        flash_param.partition_num = (flash_param.partition_num + 1) & 0x01;
        TLS_DBGPRT_INFO("switch the parameter patition number(%d).\n", flash_param.partition_num);
    } else {
        flash_param.partition_num = partition_num;
        TLS_DBGPRT_INFO("initialize the parameter patition number(%d).\n", flash_param.partition_num);
    }
    flash_param.resv_1 = flash_param.resv_2 = 0;
    flash_param.crc32 = get_crc32((u8 *)&flash_param, sizeof(flash_param) - 4);

    TLS_DBGPRT_INFO("update the parameters to parameter patition(%d) in spi flash.\n", flash_param.partition_num);

    err = tls_fls_write((flash_param.partition_num == 0) ? TLS_FLASH_PARAM1_ADDR : TLS_FLASH_PARAM2_ADDR,
        (u8 *)&flash_param, sizeof(flash_param));
    if (err != TLS_FLS_STATUS_OK) {
        TLS_DBGPRT_ERR("write to spi flash fail(%d)!\n", err);
        err = TLS_PARAM_STATUS_EIO;
        goto exit;
    }
    if (param_flash_verify((flash_param.partition_num == 0) ? TLS_FLASH_PARAM1_ADDR : TLS_FLASH_PARAM2_ADDR,
        (u8 *)&flash_param, sizeof(flash_param)) == 1) {
            err = TLS_PARAM_STATUS_OK;
    } else {
        TLS_DBGPRT_ERR("verify the parameters in spi flash fail(%d)!\n", err);
        err = TLS_PARAM_STATUS_EIO;
    }
exit:

    return err;
}

/**********************************************************************************************************
* Description:     This function is used to initial system param.
*
* Arguments  :     sys_param        is the system param addr
*

* Returns    :        TLS_PARAM_STATUS_OK        init success
*                TLS_PARAM_STATUS_EMEM        memory error
*                TLS_PARAM_STATUS_EIO        io error
*                TLS_PARAM_STATUS_EPERM
**********************************************************************************************************/
int tls_param_init(void)
{
    bool is_damage[TLS_PARAM_PARTITION_NUM];
    u8 damaged;
    int err;
    signed short i;
    u16 tryrestore = 0;
    u32 crckey = 0xFFFFFFFF;
    psCrcContext_t ctx;
    u32 crcvalue = 0;

    struct tls_param_flash *flash;

    if (flash_param.magic == TLS_PARAM_MAGIC) {
        TLS_DBGPRT_ERR("parameter management module has been initialized!\n");
        return TLS_PARAM_STATUS_EPERM;
    }

    err = tls_os_sem_create(&sys_param_lock, 1);
    if (err != TLS_OS_SUCCESS) {
        TLS_DBGPRT_ERR("create semaphore @sys_param_lock fail!\n");
        return TLS_PARAM_STATUS_EMEM;
    }

    tls_os_sem_acquire(sys_param_lock, 0);
    err = TLS_PARAM_STATUS_OK;
    i = 0;
    damaged= 0;
    is_damage[0] = is_damage[1] = FALSE;
    flash = NULL;
    memset_s(&flash_param, sizeof(flash_param), 0, sizeof(flash_param));
#if USE_TWO_RAM_FOR_PARAMETER
    memset_s(&sram_param, sizeof(sram_param), 0, sizeof(sram_param));
#endif
    tryrestore = 0;
    do {
        flash = tls_mem_alloc(sizeof(*flash));
        if (flash == NULL) {
            TLS_DBGPRT_ERR("allocate \"struct tls_param_flash\" fail!\n");
            err = TLS_PARAM_STATUS_EMEM;
            break;
        }
        memset_s(flash, sizeof(flash), 0, sizeof(*flash));

        for (i = 0; i < TLS_PARAM_PARTITION_NUM; i++) {
            TLS_DBGPRT_INFO("read parameter partition - %d.\n", i);
            tls_fls_read((i == 0) ? TLS_FLASH_PARAM1_ADDR : TLS_FLASH_PARAM2_ADDR, (u8 *)flash, sizeof(*flash));
            TLS_DBGPRT_INFO("patition %d magic - 0x%x, crc -0x%x .\n", i, flash->magic, flash->crc32);

            if (flash->magic == TLS_PARAM_MAGIC) {
                crckey = 0xFFFFFFFF;
                tls_crypto_crc_init(&ctx, crckey, CRYPTO_CRC_TYPE_32, 3);
                tls_crypto_crc_update(&ctx, (u8 *)flash, flash->length - 4);
                tls_crypto_crc_final(&ctx, &crcvalue);
            }

            if (flash->magic != TLS_PARAM_MAGIC) {
                TLS_DBGPRT_WARNING("parameter partition - %d has been damaged.\n", i);
                is_damage[i] = TRUE;
                damaged++;
                continue;
            } else if ((~crcvalue) != *(u32*)((u8*)flash + flash->length - 4)) { // 4:byte alignment
                is_damage[i] = TRUE;
                damaged++;
                continue;
            } else {
                /* Load the latest parameters */
                TLS_DBGPRT_INFO("read parameter partition modify count - %d.\n", flash->modify_count);
                TLS_DBGPRT_INFO("current parameter partition modify count - %d.\n", flash_param.modify_count);
                if ((flash_param.magic == 0) || (flash_param.modify_count < flash->modify_count)) {
                    TLS_DBGPRT_INFO("update the parameter in sram using partition - %d,%d,%d.\n",
                                    i, flash->length, sizeof(*flash));
                    if (flash->length != sizeof(*flash)) {
                        MEMCPY(&flash_param, flash, (flash->length-4));
#if USE_TWO_RAM_FOR_PARAMETER
                        MEMCPY(&sram_param, &flash_param.parameters, sizeof(sram_param));
#endif
                    } else {
                        MEMCPY(&flash_param, flash, sizeof(*flash));
#if USE_TWO_RAM_FOR_PARAMETER
                        MEMCPY(&sram_param, &flash_param.parameters, sizeof(sram_param));
#endif
                    }
                }
                memset_s(flash, sizeof(flash), 0, sizeof(*flash));
            }

            /* try to erase one sector at the same block to restore parameter area */
            if ((tryrestore == 0)&&(damaged >= TLS_PARAM_PARTITION_NUM)) {
                damaged= 0;
                is_damage[0] = is_damage[1] = FALSE;
                memset_s(&flash_param, sizeof(&flash_param), 0, sizeof(flash_param));
#if USE_TWO_RAM_FOR_PARAMETER
                memset_s(&sram_param, sizeof(&sram_param), 0, sizeof(sram_param));
#endif
                tls_fls_erase(TLS_FLASH_PARAM_RESTORE_ADDR / INSIDE_FLS_SECTOR_SIZE);
                tryrestore = 1;
                i = -1;
            }
        }

        if (damaged >= TLS_PARAM_PARTITION_NUM) {
            TLS_DBGPRT_INFO("all the parameter partitions has been demaged and load the default parameters.\n");
            tls_param_load_factory_default();

            TLS_DBGPRT_INFO("write the default parameters to all the partitions.\n");
            err = param_to_flash(TLS_PARAM_ID_ALL, 1, 0);
            if (err != TLS_PARAM_STATUS_OK) {
                TLS_DBGPRT_ERR("write the default parameters to the partitions - 0 fail!\n");
                err = TLS_PARAM_STATUS_EIO;
                break;
            }

            err = param_to_flash(TLS_PARAM_ID_ALL, 1, 1);
            if (err != TLS_PARAM_STATUS_OK) {
                TLS_DBGPRT_ERR("write the default parameters to the partitions - 1 fail!\n");
                err = TLS_PARAM_STATUS_EIO;
                break;
            }
        } else {
            /* restore damaged partitions */
            for (i = 0; i < TLS_PARAM_PARTITION_NUM; i++) {
                if (is_damage[i]) {
                    TLS_DBGPRT_INFO(" restore damaged partitions - %d.\n", i);
                    err = param_to_flash(TLS_PARAM_ID_ALL, -1, i);
                    if (err != TLS_PARAM_STATUS_OK) {
                        TLS_DBGPRT_ERR("write the default parameters to the partitions - %d fail!\n", i);
                        err = TLS_PARAM_STATUS_EIO;
                        break;
                    }
                }
            }

            if (err == TLS_PARAM_STATUS_OK) {
                break;
            }
        }
    }while (0);

    tls_os_sem_release(sys_param_lock);

    if (flash) {
        tls_mem_free(flash);
    }
    return err;
}

#define TLS_USER_MAGIC    0x574D3031    // WM01
int tls_param_load_user(struct tls_sys_param *param)
{
    u32 magic, crc32, offset;

    offset = TLS_FLASH_PARAM_DEFAULT;
    tls_fls_read(offset, (u8 *)&magic, 4);
    if (magic != TLS_USER_MAGIC) {
        TLS_DBGPRT_INFO("no user default param = %x!!!\r\n", magic);
        return TLS_PARAM_STATUS_EINVALID;
    }
    offset += 4;
    memset_s(param, sizeof(param), 0, sizeof(*param));
    tls_fls_read(offset, (u8 *)param, sizeof(struct tls_sys_param));
    offset += sizeof(struct tls_sys_param);
    tls_fls_read(offset, (u8 *)&crc32, 4);
    if (crc32 != get_crc32((u8 *)param, sizeof(struct tls_sys_param))) {
        TLS_DBGPRT_INFO("user default param crc err =%x!!!\r\n", crc32);
        return TLS_PARAM_STATUS_EINVALID;
    }
    return TLS_PARAM_STATUS_OK;
}

/**********************************************************************************************************
* Description:     This function is used to load the system default parameters.
*
* Arguments  :     param        is the param point
*

* Returns
*
* Notes    :   This function read user defined parameters first, if wrong, all the parameters restore factory settings.
**********************************************************************************************************/
void tls_param_load_factory_default(void)
{
#if USE_TWO_RAM_FOR_PARAMETER
    struct tls_sys_param *param = &sram_param;
#else
    struct tls_sys_param *param = &flash_param.parameters;
#endif

    if (param == NULL) {return;}

    TLS_DBGPRT_INFO("load the default parameters.\n");

    memset_s(param, sizeof(param), 0, sizeof(*param));
    MEMCPY(&param->hardware_version, factory_default_hardware, 8);

    param->wireless_region = TLS_PARAM_REGION_1_BG_BAND;
    param->channel = 1;
    param->channellist = 0x3FFF;
#if TLS_CONFIG_11N
    param->wbgr.bg = TLS_PARAM_PHY_11BGN_MIXED;
    param->wbgr.max_rate = TLS_PARAM_TX_RATEIDX_MCS13;
#else
    param->wbgr.bg = TLS_PARAM_PHY_11BG_MIXED;
    param->wbgr.max_rate = TLS_PARAM_TX_RATEIDX_36M;
#endif
    param->ssid_broadcast_enable = TLS_PARAM_SSIDBRD_ENABLE;
    param->encry = TLS_PARAM_ENCRY_OPEN;

    param->wireless_protocol = TLS_PARAM_IEEE80211_INFRA;

    param->auto_retrycnt = 255;
    param->auto_roam = TLS_PARAM_ROAM_DISABLE;
    param->auto_powersave = TLS_PARAM_PSM_DISABLE;
    param->auto_reconnect = 0;

    param->auto_mode = TLS_PARAM_MANUAL_MODE;
    param->transparent_trigger_length = 512;

    param->uart_cfg.baudrate = TLS_PARAM_UART_BAUDRATE_B115200;
    param->uart_cfg.stop_bits = TLS_PARAM_UART_STOPBITS_1BITS;
    param->uart_cfg.parity = TLS_PARAM_UART_PARITY_NONE;

    param->user_port_mode = TLS_PARAM_USR_INTF_LUART;

    param->ipcfg.dhcp_enable = TLS_PARAM_DHCP_ENABLE;
        param->ipcfg.ip[0] = 192;
        param->ipcfg.ip[1] = 168;
        param->ipcfg.ip[2] = 1;
        param->ipcfg.ip[3] = 1;
        param->ipcfg.netmask[0] = 255;
        param->ipcfg.netmask[1] = 255;
        param->ipcfg.netmask[2] = 255;
        param->ipcfg.netmask[3] = 0;
        param->ipcfg.gateway[0] = 192;
        param->ipcfg.gateway[1] = 168;
        param->ipcfg.gateway[2] = 1;
        param->ipcfg.gateway[3] = 1;
        param->ipcfg.dns1[0] = 192;
        param->ipcfg.dns1[1] = 168;
        param->ipcfg.dns1[2] = 1;
        param->ipcfg.dns1[3] = 1;
        param->ipcfg.dns2[0] = 192;
        param->ipcfg.dns2[1] = 168;
        param->ipcfg.dns2[2] = 1;
        param->ipcfg.dns2[3] = 1;

    strcpy_s((char *)param->local_dnsname, sizeof(param->local_dnsname), "local.winnermicro");
    strcpy_s((char *)param->local_device_name, sizeof(param->local_device_name), "w800");

    param->remote_socket_cfg.protocol = TLS_PARAM_SOCKET_TCP;
    param->remote_socket_cfg.client_or_server = TLS_PARAM_SOCKET_SERVER;
    param->remote_socket_cfg.port_num = TLS_PARAM_SOCKET_DEFAULT_PORT;
    memset_s(param->remote_socket_cfg.host, sizeof(param->remote_socket_cfg.host), 0, 32); // 32:size

    param->EscapeChar = 0x2b;
    param->EscapePeriod = 200;

    param->WebsCfg.AutoRun = 1;
    param->WebsCfg.PortNum = 80;

    param->debug_mode = 0;
    memset_s(param->PassWord, sizeof(param->PassWord), '0', 6);

    param->channel4softap = 11; // 11:byte alignment
    param->encry4softap = TLS_PARAM_ENCRY_OPEN;
    param->ipcfg4softap.dhcp_enable = TLS_PARAM_DHCP_ENABLE;
    param->ipcfg4softap.ip[0] = 192;
    param->ipcfg4softap.ip[1] = 168;
    param->ipcfg4softap.ip[2] = 0;
    param->ipcfg4softap.ip[3] = 1;
    param->ipcfg4softap.netmask[0] = 255;
    param->ipcfg4softap.netmask[1] = 255;
    param->ipcfg4softap.netmask[2] = 255;
    param->ipcfg4softap.netmask[3] = 0;
    param->ipcfg4softap.gateway[0] = 192;
    param->ipcfg4softap.gateway[1] = 168;
    param->ipcfg4softap.gateway[2] = 0;
    param->ipcfg4softap.gateway[3] = 1;
    param->ipcfg4softap.dns1[0] = 192;
    param->ipcfg4softap.dns1[1] = 168;
    param->ipcfg4softap.dns1[2] = 0;
    param->ipcfg4softap.dns1[3] = 1;
    param->ipcfg4softap.dns2[0] = 0;
    param->ipcfg4softap.dns2[1] = 0;
    param->ipcfg4softap.dns2[2] = 0;
    param->ipcfg4softap.dns2[3] = 0;
#if TLS_CONFIG_SOFTAP_11N
    param->wbgr4softap.bg = TLS_PARAM_PHY_11BGN_MIXED;
    param->wbgr4softap.max_rate = TLS_PARAM_TX_RATEIDX_36M;
#else
    param->wbgr4softap.bg = TLS_PARAM_PHY_11BG_MIXED;
    param->wbgr4softap.max_rate = TLS_PARAM_TX_RATEIDX_36M;
#endif

    strcpy_s(param->sntp_service1, sizeof(param->sntp_service1), "cn.ntp.org.cn");
    strcpy_s(param->sntp_service2, sizeof(param->sntp_service2), "ntp.sjtu.edu.cn");
    strcpy_s(param->sntp_service3, sizeof(param->sntp_service3), "us.pool.ntp.org");
}

/**********************************************************************************************************
* Description:     This function is used to set system parameter.
*
* Arguments  :     id        param id,from TLS_PARAM_ID_SSID to (TLS_PARAM_ID_MAX - 1)
*                argc        store parameters
*                to_flash    whether the parameter is written to flash,1 write

* Returns    :        TLS_PARAM_STATUS_OK        set success
*                TLS_PARAM_STATUS_EINVALID    invalid param
**********************************************************************************************************/
int tls_param_set(int id, void *argv, bool to_flash)
{
    int err = 0;
#if USE_TWO_RAM_FOR_PARAMETER
    struct tls_sys_param *param = &sram_param;
#else
    struct tls_sys_param *param = &flash_param.parameters;
#endif
    if ((id < TLS_PARAM_ID_ALL) || (id >= TLS_PARAM_ID_MAX) || (argv == NULL)) {return TLS_PARAM_STATUS_EINVALID;}

    if (updp_mode) {
        param = tls_param_user_param_init();
        if (param == NULL) {
            return TLS_PARAM_STATUS_EMEM;
        }
    }
    tls_os_sem_acquire(sys_param_lock, 0);

    err = TLS_PARAM_STATUS_OK;
    switch (id) {
        case TLS_PARAM_ID_ALL:
            MEMCPY(param, argv, sizeof(struct tls_sys_param));
            break;

        case TLS_PARAM_ID_SSID:
            MEMCPY(&param->ssid, argv, sizeof(struct tls_param_ssid));
            break;

        case TLS_PARAM_ID_ENCRY:
            param->encry = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_KEY:
            MEMCPY(&param->key, argv, sizeof(struct tls_param_key));
            break;

        case TLS_PARAM_ID_IP:
            MEMCPY(&param->ipcfg, argv, sizeof(struct tls_param_ip));
            break;

        case TLS_PARAM_ID_AUTOMODE:
            param->auto_mode = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_DEFSOCKET:
            MEMCPY(&param->remote_socket_cfg, argv, sizeof(struct tls_param_socket));
            break;

        case TLS_PARAM_ID_BSSID:
            MEMCPY(&param->bssid, argv, sizeof(struct tls_param_bssid));
            break;

        case TLS_PARAM_ID_CHANNEL:
            param->channel = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_CHANNEL_LIST:
            param->channellist = *((u16*)argv);
            break;

        case TLS_PARAM_ID_CHANNEL_EN:
            param->channel_enable = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_COUNTRY_REGION:
            param->wireless_region = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_WPROTOCOL:
            param->wireless_protocol = *((u8 *)argv);;
            break;

        case TLS_PARAM_ID_ADHOC_AUTOCREATE:
            param->auto_create_adhoc = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_ROAMING:
            param->auto_roam = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_AUTO_RETRY_CNT:
            param->auto_retrycnt = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_WBGR:
            MEMCPY(&param->wbgr, argv, sizeof(struct tls_param_bgr));
            break;

        case TLS_PARAM_ID_USRINTF:
            param->user_port_mode = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_AUTO_TRIGGER_LENGTH:
            param->transparent_trigger_length = *((u16 *)argv);
            break;

        case TLS_PARAM_ID_AUTO_TRIGGER_PERIOD:
            param->transparent_trigger_period = *((u16 *)argv);
            break;

        case TLS_PARAM_ID_ESCAPE_CHAR:
            param->EscapeChar = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_ESCAPE_PERIOD:
            param->EscapePeriod = *((u16 *)argv);
            break;

        case TLS_PARAM_ID_IO_MODE:
            param->IoMode = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_CMD_MODE:
            param->CmdMode = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_PASSWORD:
            MEMCPY(param->PassWord, (u8 *)argv, sizeof(param->PassWord));
            break;
        case TLS_PARAM_ID_WEBS_CONFIG:
            param->WebsCfg = *((struct tls_webs_cfg *)argv);
            break;
        case TLS_PARAM_ID_DEBUG_MODE:
            param->debug_mode = *((u32 *)argv);;
            break;

        case TLS_PARAM_ID_HARDVERSION:
            MEMCPY(&param->hardware_version, argv, sizeof(struct tls_param_hardware_version));
            break;

        case TLS_PARAM_ID_BRDSSID:
            param->ssid_broadcast_enable = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_DNSNAME:
            strcpy_s((char *)param->local_dnsname, sizeof(param->local_dnsname), (char *)argv);
            break;

        case TLS_PARAM_ID_DEVNAME:
            strcpy_s((char *)param->local_device_name, sizeof(param->local_device_name), argv);
            break;

        case TLS_PARAM_ID_PSM:
            param->auto_powersave = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_ORAY_CLIENT:
            MEMCPY(&param->oray_client_setting, argv, sizeof(struct tls_param_oray_client));
            break;

        case TLS_PARAM_ID_UPNP:
            param->upnp_enable = *((u8 *)argv);
            break;

        case TLS_PARAM_ID_UART:
            MEMCPY(&param->uart_cfg, argv, sizeof(struct tls_param_uart));
            break;
#if TLS_CONFIG_WPS
        case TLS_PARAM_ID_WPS:
            MEMCPY(&param->wps, argv, sizeof(struct tls_param_wps));
            break;
#endif
        case TLS_PARAM_ID_ONESHOT_CFG:
            param->oneshotflag = *((u8 *)argv);
            break;
        case TLS_PARAM_ID_SHA1:
            MEMCPY(&param->psk, (u8 *)argv, sizeof(struct tls_param_sha1));

            break;
        case TLS_PARAM_ID_ORIGIN_KEY:
            MEMCPY(&param->original_key, (u8*)argv, sizeof(struct tls_param_original_key));
            break;
        case TLS_PARAM_ID_ORIGIN_SSID:
            MEMCPY(&param->original_ssid, (u8*)argv, sizeof(struct tls_param_ssid));
            break;
        case TLS_PARAM_ID_AUTO_RECONNECT:
            param->auto_reconnect = *((u8 *)argv);
            break;
        case TLS_PARAM_ID_QUICK_CONNECT:
            MEMCPY(&param->quick_connect, argv, sizeof(struct tls_param_quick_connect));
            break;
        case TLS_PARAM_ID_KEY_CHANGE:
            param->key_changed = *((u8 *)argv);
            break;
        case TLS_PARAM_ID_SSID_CHANGE:
            param->ssid_changed = *((u8 *)argv);
            break;
#if TLS_CONFIG_AP
        case TLS_PARAM_ID_SOFTAP_SSID:
            MEMCPY(&param->apsta_ssid, argv, sizeof(struct tls_param_ssid));
            break;
        case TLS_PARAM_ID_SOFTAP_PSK:
            MEMCPY(&param->apsta_psk, argv, sizeof(struct tls_param_sha1));
            break;
        case TLS_PARAM_ID_SOFTAP_ENCRY:
            param->encry4softap = *((u8 *)argv);
            break;
        case TLS_PARAM_ID_SOFTAP_KEY:
            MEMCPY(&param->key4softap, argv, sizeof(struct tls_param_key));
            break;
        case TLS_PARAM_ID_SOFTAP_IP:
            MEMCPY(&param->ipcfg4softap, argv, sizeof(struct tls_param_ip));
            break;
        case TLS_PARAM_ID_SOFTAP_CHANNEL:
            param->channel4softap = *((u8 *)argv);
            break;
        case TLS_PARAM_ID_SOFTAP_WBGR:
            MEMCPY(&param->wbgr4softap, argv, sizeof(struct tls_param_bgr));
            break;
#endif
        case TLS_PARAM_ID_SNTP_SERVER1:
            strncpy_s(param->sntp_service1, sizeof(param->sntp_service1), (const char *)argv, strlen(argv) + 1);
            break;
        case TLS_PARAM_ID_SNTP_SERVER2:
            strncpy_s(param->sntp_service2, sizeof(param->sntp_service2), (const char *)argv, strlen(argv) + 1);
            break;
        case TLS_PARAM_ID_SNTP_SERVER3:
            strncpy_s(param->sntp_service3, sizeof(param->sntp_service3), (const char *)argv, strlen(argv) + 1);
            break;
        case TLS_PARAM_ID_TEM_OFFSET:
            MEMCPY(&param->params_tem, argv, sizeof(struct tls_param_tem_offset));
            break;

        case TLS_PARAM_ID_BT_ADAPTER:
            MEMCPY(&param->adapter_t, argv,  sizeof(bt_adapter_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_1:
            MEMCPY(&param->remote_device1, argv, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_2:
            MEMCPY(&param->remote_device2, argv, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_3:
            MEMCPY(&param->remote_device3, argv, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_4:
            MEMCPY(&param->remote_device4, argv, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_5:
            MEMCPY(&param->remote_device5, argv, sizeof(bt_remote_device_t));
            break;
        default:
            TLS_DBGPRT_WARNING("invalid parameter id - %d!\n", id);
            err = TLS_PARAM_STATUS_EINVALIDID;
            goto exit;
    }

    if (to_flash && !updp_mode) {
        err = param_to_flash(id, -1, -1);
        TLS_DBGPRT_INFO("write the parameter to spi flash - %d.\n", err);
    }
exit:
    tls_os_sem_release(sys_param_lock);

    return err;
}

/**********************************************************************************************************
* Description:     This function is used to get system parameter.
*
* Arguments  :     id        param id,from TLS_PARAM_ID_SSID to (TLS_PARAM_ID_MAX - 1)
*                argc        store parameters
*                from_flash    whether the parameter is readed from flash,1 read from flash

* Returns    :        TLS_PARAM_STATUS_OK    success
*                TLS_PARAM_STATUS_EINVALID    invalid param
**********************************************************************************************************/
int tls_param_get(int id, void *argv, bool from_flash)
{
    int err;
    struct tls_sys_param *src = NULL;

    if ((id < TLS_PARAM_ID_ALL) || (id >= TLS_PARAM_ID_MAX)) {return TLS_PARAM_STATUS_EINVALID;}

    err = TLS_PARAM_STATUS_OK;
#if USE_TWO_RAM_FOR_PARAMETER
    if (from_flash) {
        src = &flash_param.parameters;
    } else {src = &sram_param;}
#else
    struct tls_param_flash *curflashparm = NULL;
    if (from_flash) {
        curflashparm = tls_mem_alloc(sizeof(struct tls_param_flash));
        if (curflashparm) {
            if (TLS_FLS_STATUS_OK == tls_fls_read((flash_param.partition_num == 0) ? TLS_FLASH_PARAM1_ADDR : \
                TLS_FLASH_PARAM2_ADDR, (u8 *)curflashparm, sizeof(struct tls_param_flash))) {
                src = &curflashparm->parameters;
            }
        }
    }

    if (src == NULL) {
        src = &flash_param.parameters;
    }
#endif

    tls_os_sem_acquire(sys_param_lock, 0);

    switch (id) {
        case TLS_PARAM_ID_ALL:
            MEMCPY(argv, src, sizeof(struct tls_sys_param));
            break;

        case TLS_PARAM_ID_SSID:
            MEMCPY(argv, &src->ssid, sizeof(struct tls_param_ssid));
            break;

        case TLS_PARAM_ID_ENCRY:
            *((u8 *)argv) = src->encry;
            break;

        case TLS_PARAM_ID_KEY:
            MEMCPY(argv, &src->key, sizeof(struct tls_param_key));
            break;

        case TLS_PARAM_ID_IP:
            MEMCPY(argv, &src->ipcfg, sizeof(struct tls_param_ip));
            break;

        case TLS_PARAM_ID_AUTOMODE:
            *((u8 *)argv) = src->auto_mode;
            break;

        case TLS_PARAM_ID_DEFSOCKET:
            MEMCPY(argv, &src->remote_socket_cfg, sizeof(struct tls_param_socket));
            break;

        case TLS_PARAM_ID_BSSID:
            MEMCPY(argv, &src->bssid, sizeof(struct tls_param_bssid));
            break;

        case TLS_PARAM_ID_CHANNEL:
            *((u8 *)argv) = src->channel;
            break;
        case TLS_PARAM_ID_CHANNEL_LIST:
            *((u16*)argv) = src->channellist;
            break;

        case TLS_PARAM_ID_CHANNEL_EN:
            *((u8 *)argv) = src->channel_enable;
            break;

        case TLS_PARAM_ID_COUNTRY_REGION:
            *((u8 *)argv) = src->wireless_region;
            break;

        case TLS_PARAM_ID_WPROTOCOL:
            *((u8 *)argv) = src->wireless_protocol;
            break;

        case TLS_PARAM_ID_ADHOC_AUTOCREATE:
            *((u8 *)argv) = src->auto_create_adhoc;
            break;

        case TLS_PARAM_ID_ROAMING:
            *((u8 *)argv) = src->auto_roam;
            break;

        case TLS_PARAM_ID_AUTO_RETRY_CNT:
            *((u8 *)argv) = src->auto_retrycnt;
            break;

        case TLS_PARAM_ID_WBGR:
            MEMCPY(argv, &src->wbgr, sizeof(struct tls_param_bgr));
            break;

        case TLS_PARAM_ID_USRINTF:
            *((u8 *)argv) = src->user_port_mode;
            break;

        case TLS_PARAM_ID_AUTO_TRIGGER_LENGTH:
            *((u16 *)argv) = src->transparent_trigger_length;
            break;
        case TLS_PARAM_ID_AUTO_TRIGGER_PERIOD:
            *((u16 *)argv) = src->transparent_trigger_period;
            break;

        case TLS_PARAM_ID_ESCAPE_CHAR:
            *((u8 *)argv) = src->EscapeChar;
            break;

        case TLS_PARAM_ID_ESCAPE_PERIOD:
            *((u16 *)argv) = src->EscapePeriod;
            break;
        case TLS_PARAM_ID_IO_MODE:
            *((u8 *)argv) = src->IoMode;
            break;
        case TLS_PARAM_ID_CMD_MODE:
            *((u8 *)argv) = src->CmdMode;
            break;

        case TLS_PARAM_ID_PASSWORD:
            MEMCPY((u8 *)argv, src->PassWord, sizeof(src->PassWord));
            break;
        case TLS_PARAM_ID_WEBS_CONFIG:
            *((struct tls_webs_cfg *)argv) = src->WebsCfg;
            break;

        case TLS_PARAM_ID_DEBUG_MODE:
            *((u32 *)argv) = src->debug_mode;
            break;

        case TLS_PARAM_ID_HARDVERSION:
            MEMCPY(argv, &src->hardware_version, sizeof(struct tls_param_hardware_version));
            break;

        case TLS_PARAM_ID_BRDSSID:
            *((u8 *)argv) = src->ssid_broadcast_enable;
            break;

        case TLS_PARAM_ID_DNSNAME:
            strcpy_s((char *)argv, sizeof(argv), (char *)src->local_dnsname);
            break;

        case TLS_PARAM_ID_DEVNAME:
            strcpy_s((char *)argv, sizeof(argv), (char *)src->local_device_name);
            break;

        case TLS_PARAM_ID_PSM:
            *((u8 *)argv) = src->auto_powersave;
            break;

        case TLS_PARAM_ID_ORAY_CLIENT:
            MEMCPY(argv, &src->oray_client_setting, sizeof(struct tls_param_oray_client));
            break;

        case TLS_PARAM_ID_UPNP:
            *((u8 *)argv) = src->upnp_enable;
            break;

        case TLS_PARAM_ID_UART:
            MEMCPY(argv, &src->uart_cfg, sizeof(struct tls_param_uart));
            break;
#if TLS_CONFIG_WPS
        case TLS_PARAM_ID_WPS:
            MEMCPY(argv, &src->wps, sizeof(struct tls_param_wps));
            break;
#endif
        case TLS_PARAM_ID_ONESHOT_CFG:
            *((u8 *)argv) = src->oneshotflag;
            break;
        case TLS_PARAM_ID_SHA1:
            MEMCPY(argv, &src->psk, sizeof(struct tls_param_sha1));

            break;
        case TLS_PARAM_ID_ORIGIN_KEY:
            MEMCPY(argv, &src->original_key, sizeof(struct tls_param_original_key));
            break;
        case TLS_PARAM_ID_ORIGIN_SSID:
            MEMCPY(argv, &src->original_ssid, sizeof(struct tls_param_ssid));
            break;
        case TLS_PARAM_ID_AUTO_RECONNECT:
            *((u8 *)argv) = src->auto_reconnect;
            break;
        case TLS_PARAM_ID_QUICK_CONNECT:
            MEMCPY(argv, &src->quick_connect, sizeof(struct tls_param_quick_connect));
            break;
        case TLS_PARAM_ID_KEY_CHANGE:
            *((u8 *)argv) = src->key_changed;
            break;
        case TLS_PARAM_ID_SSID_CHANGE:
            *((u8 *)argv) = src->ssid_changed;
            break;
#if TLS_CONFIG_AP
        case TLS_PARAM_ID_SOFTAP_SSID:
            MEMCPY(argv, &src->apsta_ssid, sizeof(struct tls_param_ssid));
            break;
        case TLS_PARAM_ID_SOFTAP_PSK:
            MEMCPY(argv, &src->apsta_psk, sizeof(struct tls_param_sha1));
            break;
        case TLS_PARAM_ID_SOFTAP_ENCRY:
            *((u8 *)argv) = src->encry4softap;
            break;
        case TLS_PARAM_ID_SOFTAP_KEY:
            MEMCPY(argv, &src->key4softap, sizeof(struct tls_param_key));
            break;
        case TLS_PARAM_ID_SOFTAP_IP:
            MEMCPY(argv, &src->ipcfg4softap, sizeof(struct tls_param_ip));
            break;
        case TLS_PARAM_ID_SOFTAP_CHANNEL:
            *((u8 *)argv) = src->channel4softap;
            break;
        case TLS_PARAM_ID_SOFTAP_WBGR:
            MEMCPY(argv, &src->wbgr4softap, sizeof(struct tls_param_bgr));
            break;
#endif

        case TLS_PARAM_ID_SNTP_SERVER1:
            strncpy_s(argv, sizeof(argv), src->sntp_service1, strlen(src->sntp_service1)+1);
            break;
        case TLS_PARAM_ID_SNTP_SERVER2:
            strncpy_s(argv, sizeof(argv), src->sntp_service2, strlen(src->sntp_service2)+1);
            break;
        case TLS_PARAM_ID_SNTP_SERVER3:
            strncpy_s(argv, sizeof(argv), src->sntp_service3, strlen(src->sntp_service3)+1);
            break;
        case TLS_PARAM_ID_TEM_OFFSET:
            MEMCPY(argv, &src->params_tem, sizeof(struct tls_param_tem_offset));
            break;

        case TLS_PARAM_ID_BT_ADAPTER:
            MEMCPY(argv, &src->adapter_t,   sizeof(bt_adapter_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_1:
            MEMCPY(argv, &src->remote_device1,  sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_2:
            MEMCPY(argv, &src->remote_device2, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_3:
            MEMCPY(argv, &src->remote_device3, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_4:
            MEMCPY(argv, &src->remote_device4, sizeof(bt_remote_device_t));
            break;
        case TLS_PARAM_ID_BT_REMOTE_DEVICE_5:
            MEMCPY(argv, &src->remote_device5, sizeof(bt_remote_device_t));
            break;
        default:
            TLS_DBGPRT_WARNING("invalid parameter id - %d!\n", id);
            err = TLS_PARAM_STATUS_EINVALIDID;
            break;
    }
#if USE_TWO_RAM_FOR_PARAMETER
#else
    if (curflashparm) {
        tls_mem_free(curflashparm);
    }
#endif

    tls_os_sem_release(sys_param_lock);

    return err;
}

/**********************************************************************************************************
* Description:     This function is used to write parameter to flash.
*
* Arguments  :     id        param id,from TLS_PARAM_ID_ALL to (TLS_PARAM_ID_MAX - 1)
*
* Returns    :        * Returns    :        TLS_PARAM_STATUS_OK    success
*                TLS_PARAM_STATUS_EINVALID    invalid param
*                TLS_PARAM_STATUS_EIO        error
**********************************************************************************************************/
int tls_param_to_flash(int id)
{
    int err = 0;

    tls_os_sem_acquire(sys_param_lock, 0);
#if USE_TWO_RAM_FOR_PARAMETER
    if (TLS_PARAM_ID_ALL == id) {
        if (memcmp(&sram_param, &flash_param.parameters, sizeof(sram_param) == 0)) {
            tls_os_sem_release(sys_param_lock);
            return TLS_FLS_STATUS_OK;
        }
    }
    err = param_to_flash(id, -1, -1);
#else
    if (TLS_PARAM_ID_ALL == id) {
        struct tls_param_flash *sram_param;
        sram_param = tls_mem_alloc(sizeof(struct tls_param_flash));
        if (sram_param) {
            if (TLS_FLS_STATUS_OK != tls_fls_read((flash_param.partition_num == 0) ? TLS_FLASH_PARAM1_ADDR : \
                TLS_FLASH_PARAM2_ADDR, (u8 *)sram_param, sizeof(struct tls_param_flash))) {
                /* write anyway!!! */
            } else {    /* if not same, write to flash */
                if (memcmp(&sram_param->parameters, &flash_param.parameters, sizeof(struct tls_sys_param)) == 0) {
                    tls_mem_free(sram_param);
                    tls_os_sem_release(sys_param_lock);
                    return TLS_FLS_STATUS_OK;
                }
            }
            tls_mem_free(sram_param);
        }
    }

    err = param_to_flash(id, -1, -1);
#endif
    tls_os_sem_release(sys_param_lock);

    return err;
}

/**********************************************************************************************************
* Description:     This function is used to load default parametes to memory.
*
* Notes  :   This function read user defined parameters first, if wrong, all the parameters restore factory settings.
**********************************************************************************************************/
int tls_param_to_default(void)
{
    int err = 0;
    tls_param_load_factory_default();
    err = param_to_flash(TLS_PARAM_ID_ALL, 1, 0);
    if (err) {
        return err;
    }
    err = param_to_flash(TLS_PARAM_ID_ALL, 1, 1);
    flash_param.magic = 0;

    return err;
}

struct tls_sys_param *tls_param_user_param_init(void)
{
    if (user_default_param == NULL) {
        user_default_param = tls_mem_alloc(sizeof(*user_default_param));
        if (user_default_param) {
            memset_s(user_default_param, sizeof(user_default_param), 0, sizeof(*user_default_param));
        }
    }

    return user_default_param;
}

/**********************************************************************************************************
* Description:     This function is used to modify user default parameters,then write to flash.
**********************************************************************************************************/
int tls_param_save_user(struct tls_user_param *user_param)
{
    struct tls_sys_param *param = tls_param_user_param_init();
    if (param == NULL) {
        return TLS_PARAM_STATUS_EMEM;
    }

    param->wireless_protocol = user_param->wireless_protocol;
    param->auto_mode = user_param->auto_mode;
    param->uart_cfg.baudrate = user_param->baudrate;
    param->user_port_mode = user_param->user_port_mode;
    param->ipcfg.dhcp_enable = user_param->dhcp_enable;
    param->auto_powersave = user_param->auto_powersave;

    MEMCPY(param->ipcfg.ip, user_param->ip, 4);
    MEMCPY(param->ipcfg.netmask, user_param->netmask, 4);
    MEMCPY(param->ipcfg.gateway, user_param->gateway, 4);
    MEMCPY(param->ipcfg.dns1, user_param->dns, 4);
    MEMCPY(param->ipcfg.dns2, user_param->dns, 4);
    param->remote_socket_cfg.protocol = user_param->socket_protocol;
    param->remote_socket_cfg.client_or_server = user_param->socket_client_or_server;
    param->remote_socket_cfg.port_num = user_param->socket_port_num;
    MEMCPY(param->remote_socket_cfg.host, user_param->socket_host, 32);
    MEMCPY(param->PassWord, user_param->PassWord, 6);

    MEMCPY(&param->hardware_version, factory_default_hardware, 8);
    param->wireless_region = TLS_PARAM_REGION_1_BG_BAND;
    param->channel = 1;
    param->channellist = 0x3FFF;
    param->wbgr.bg = TLS_PARAM_PHY_11BG_MIXED;
    param->wbgr.max_rate = TLS_PARAM_TX_RATEIDX_36M;
    param->ssid_broadcast_enable = TLS_PARAM_SSIDBRD_ENABLE;
    param->encry = TLS_PARAM_ENCRY_OPEN;

    param->auto_retrycnt = 255;
    param->auto_roam = TLS_PARAM_ROAM_DISABLE;

    param->transparent_trigger_length = 512;

    param->uart_cfg.stop_bits = TLS_PARAM_UART_STOPBITS_1BITS;
    param->uart_cfg.parity = TLS_PARAM_UART_PARITY_NONE;

    strcpy_s((char *)param->local_dnsname, sizeof(param->local_dnsname), "local.winnermicro");
    strcpy_s((char *)param->local_device_name, sizeof(param->local_device_name), "w800");

    param->EscapeChar = 0x2b;
    param->EscapePeriod = 200;

    param->debug_mode = 0;

    tls_param_save_user_default();

    return TLS_PARAM_STATUS_OK;
}

/**********************************************************************************************************
* Description:     This function is used to save user parameters to the flash.
**********************************************************************************************************/
int tls_param_save_user_default(void)
{
    u32 magic, crc32, offset;
    if (user_default_param == NULL) {
        return TLS_PARAM_STATUS_EMEM;
    }

    offset = TLS_FLASH_PARAM_DEFAULT;
    magic = TLS_USER_MAGIC;
    TLS_DBGPRT_INFO("=====>\n");
    tls_fls_write(offset, (u8 *)&magic, 4);
    offset += 4;
    tls_fls_write(offset, (u8 *)user_default_param, sizeof(struct tls_sys_param));
    offset += sizeof(struct tls_sys_param);
    crc32 = get_crc32((u8 *)user_default_param, sizeof(struct tls_sys_param));
    tls_fls_write(offset, (u8 *)&crc32, 4);

    return TLS_PARAM_STATUS_OK;
}

u8 tls_param_get_updp_mode(void)
{
    return updp_mode;
}

void tls_param_set_updp_mode(u8 mode)
{
    updp_mode = mode;
}

